<?php

namespace Henan\ThinkSdk\helper;


/**
 * 常用函数类
 * @author henan
 */
class FC
{
    /**
     * 当前日期
     * @return string
     */
    public static function date(): string
    {
        return date('Y-m-d');
    }

    /**
     * 当前时间
     * @return string
     */
    public static function datetime(): string
    {
        return date('Y-m-d H:i:s');
    }

    /**
     * 获取域名
     * @return mixed|string
     */
    public static function getDomain(): mixed
    {
        return $_SERVER['HTTP_HOST'] ?? '';
    }

    /**
     * 获取IP
     * @return string
     */
    public static function getIp(): string
    {
        try {
            $ip = $_SERVER['REMOTE_ADDR'] ?? '';
            if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
                $ip = $_SERVER['HTTP_CLIENT_IP'];
            } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
            } elseif (!empty($_SERVER['HTTP_X_FORWARDED'])) {
                $ip = $_SERVER['HTTP_X_FORWARDED'];
            } elseif (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) {
                $ip = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
            } elseif (!empty($_SERVER['HTTP_FORWARDED_FOR'])) {
                $ip = $_SERVER['HTTP_FORWARDED_FOR'];
            } elseif (!empty($_SERVER['HTTP_FORWARDED'])) {
                $ip = $_SERVER['HTTP_FORWARDED'];
            }
            return (string)$ip;
        } catch (\Exception $e) {
            return '';
        }
    }

    /**
     * 获取请求地址
     * @return string
     */
    public static function getUrl(): string
    {
        $url = app('http')->getName() . '/' . \think\facade\Request::pathinfo();
        return str_starts_with($url, '/') ? $url : '/' . $url;
    }

    /**
     * 生成唯一编号
     * @param string $prefix 前缀
     * @param int $length 随机数长度
     * @param string $dateFormat 时间字符串格式
     * @return string
     */
    public static function getNumber(string $prefix = '', int $length = 5, string $dateFormat = 'YmdHis'): string
    {
        $dateStr = $dateFormat ? date($dateFormat) : '';
        $min = pow(10, $length - 1);
        $max = pow(10, $length) - 1;
        $randomNumber = mt_rand($min, $max);
        $randStr = str_pad((string)$randomNumber, $length, '0', STR_PAD_LEFT);
        return $prefix . $dateStr . $randStr;
    }

    /**
     * 随机字符串生成
     * @param int $length 字符串长度
     * @param bool $is_upper 是否大写
     * @return string
     */
    public static function getRandStr(int $length = 128, bool $is_upper = false): string
    {
        $str = '';
        $rang = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm";
        for ($i = 0; $i < $length; $i++) $str .= $rang[rand(0, 60)];
        return $is_upper ? strtoupper($str) : $str;
    }

    /**
     * URL拼接
     * @param $url
     * @param $param
     * @return string
     */
    public static function urlJoin($url, $param): string
    {
        if (str_contains($url, '?')) {
            return $url . '&' . http_build_query($param);
        } else {
            return $url . '?' . http_build_query($param);
        }
    }

    /**
     * 数组是否为关联数组
     * @param array $arr
     * @return bool
     */
    public static function arrIsAssoc(array $arr): bool
    {
        if (empty($arr)) return false;
        return array_keys($arr) !== range(0, count($arr) - 1);
    }

    /**
     * 数组转字符串
     * @param array|null $arr
     * @param string $separator
     * @return string
     */
    public static function arrToStr(array|null $arr, string $separator = ','): string
    {
        if (is_array($arr)) {
            return implode($separator, array_filter($arr));
        } else {
            return '';
        }
    }

    /**
     * 字符串转数组
     * @param string|null $str
     * @param string $separator
     * @param bool $is_int
     * @return string[]
     */
    public static function strToArr(string|null $str, string $separator = ',', bool $is_int = false): array
    {
        if ($str === null || $str === '') return [];
        $arr = array_filter(explode($separator, trim($str)));
        if ($is_int) {
            foreach ($arr as &$item) $item = (integer)$item;
        }
        return $arr;
    }

    /**
     * 字符串截取
     * @param $str
     * @param int $len
     * @return mixed|string
     */
    public static function strCut($str, int $len = 30): mixed
    {
        return strlen($str) > $len ? substr($str, 0, $len) : $str;
    }

    /**
     * 多维数组合并
     * @param array $list
     * @param string $separator
     * @return array
     */
    public static function arrMultiMerge(array $list, string $separator = ','): array
    {
        $arr = [];
        foreach ($list as $value) $arr = is_array($value) ? array_merge($arr, $value) : array_merge($arr, explode($separator, $value));
        return array_values(array_unique(array_filter($arr)));
    }

    /**
     * 距今时间
     * @param $time
     * @return string
     */
    public static function timeAgo($time): string
    {
        $t = time() - strtotime($time);
        if ($t >= 0) {
            $f = ['31536000' => '年', '2592000' => '个月', '604800' => '星期', '86400' => '天', '3600' => '小时', '60' => '分钟', '1' => '秒'];
            foreach ($f as $k => $v) {
                if (0 != $c = floor($t / (int)$k)) return $c . $v . '前';
            }
        }
        return '';
    }

    /**
     * 网络请求
     * @param string $url 请求地址
     * @param array $param 请求参数
     * @param string $method 请求方法
     * @param array $headers 请求头
     * @param bool $isJson 是否JSON请求
     * @param int $jsonFlags JSON编码
     * @return mixed
     */
    public static function curl(string $url, array $param, string $method = 'get', array $headers = [], bool $isJson = true, int $jsonFlags = JSON_FORCE_OBJECT): mixed
    {
        $head = [];
        $curl = curl_init();
        $method = strtoupper($method);
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        if (in_array($method, ['POST', 'PUT', 'PATCH'])) {
            if ($isJson) {
                $head[] = 'Content-Type: application/json; charset=utf-8';
                curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($param, $jsonFlags));
            } else {
                curl_setopt($curl, CURLOPT_POSTFIELDS, $param);
            }
        }
        if (in_array($method, ['GET', 'DELETE'])) {
            $url .= '?' . http_build_query($param);
        }
        foreach ($headers as $key => $item) $head[] = "$key:$item";
        curl_setopt($curl, CURLOPT_HTTPHEADER, $head);
        curl_setopt($curl, CURLOPT_URL, $url);
        if (str_starts_with($url, "https://")) {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($curl);
        curl_close($curl);
        return json_decode($result, true);
    }

    /**
     * 下划线转驼峰
     * @param string $str
     * @return array|string|null
     */
    public static function lineToHump(string $str): array|string|null
    {
        return preg_replace_callback('/([-_]+([a-z]))/i', function ($matches) {
            return strtoupper($matches[2]);
        }, $str);
    }

    /**
     * 驼峰转下划线
     * @param string $str
     * @return null|string|string[]
     */
    public static function humpToLine(string $str): array|string|null
    {
        return preg_replace_callback('/([A-Z])/', function ($matches) {
            return '_' . strtolower($matches[0]);
        }, $str);
    }

    /**
     * 获取真实IP
     * @return mixed
     */
    public static function getRealIp(): mixed
    {
        $ip = $_SERVER['REMOTE_ADDR'];
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
            foreach ($matches[0] as $xip) {
                if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
                    $ip = $xip;
                    break;
                }
            }
        } elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) {
            $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
        } elseif (isset($_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) {
            $ip = $_SERVER['HTTP_X_REAL_IP'];
        }
        return $ip;
    }

    /**
     * 读取文件夹下的所有文件
     * @param string $path
     * @param string $basePath
     * @return array
     */
    public static function readDirAllFiles(string $path, string $basePath = ''): array
    {
        list($list, $temp_list) = [[], scandir($path)];
        empty($basePath) && $basePath = $path;
        foreach ($temp_list as $file) {
            if ($file != ".." && $file != ".") {
                if (is_dir($path . DIRECTORY_SEPARATOR . $file)) {
                    $childFiles = self::readDirAllFiles($path . DIRECTORY_SEPARATOR . $file, $basePath);
                    $list = array_merge($childFiles, $list);
                } else {
                    $filePath = $path . DIRECTORY_SEPARATOR . $file;
                    $fileName = str_replace($basePath . DIRECTORY_SEPARATOR, '', $filePath);
                    $list[$fileName] = $filePath;
                }
            }
        }
        return $list;
    }

    /**
     * 模板值替换
     * @param $string
     * @param $array
     * @return mixed
     */
    public static function replaceTemplate($string, $array): mixed
    {
        foreach ($array as $key => $val) {
            $string = str_replace("{{" . $key . "}}", $val, $string);
        }
        return $string;
    }

    /**
     * 获取偏移天数后的日期字符串
     * @param int $offsetDays 天数偏移值（正数为未来日期，负数为过去日期）
     * @param string $dateFormat 日期字符串格式（默认为'Y-m-d'）
     * @return string 格式化后的日期字符串
     */
    public static function getOffsetDate(int $offsetDays = 0, string $dateFormat = 'Y-m-d'): string
    {
        // 获取当前时间戳
        $timestamp = time();
        // 计算偏移天数后的时间戳
        $offsetTimestamp = strtotime("+$offsetDays days", $timestamp);
        // 格式化为指定的日期字符串
        return date($dateFormat, $offsetTimestamp);
    }
}